<script setup>
import {
    reactive,
    ref,
    onMounted,
    onUnmounted,
    getCurrentInstance
} from "vue";
import { showToast, closeToast } from "vant";
import Recorder from "recorder-core";
import "recorder-core/src/engine/pcm";
import { marked } from "marked";
import sanitizeHtml from "sanitize-html";
import huatong from "@/assets/img/huatong.png";
import { useChatStore } from "@/store/index";
import IatService from "@/utils/iat/index";
import RecorderManager from "@/utils/iat/dist/index.esm"; 
import path from "path-browserify";
const {
    proxy: { $http },
} = getCurrentInstance();

const emits = defineEmits(["send", "add", "answer"]);
// 讯飞语音听写配置
const appId = '7cf019c8';
const apiKey = 'a0a7c5cc3d0c4d5a8fda57fa379d2bbc';
const apiSecret = 'YjY4YmRmMjViN2E1ZDk5NDU1MjFmOTJm';
const iatService = ref(null);
const recorder = ref(null);

const dataVal = reactive({
    huatong,
    recording: false,
    showRecordingPopup: false,
    isCanceling: false,
    recordingDuration: 0,
    volumeLevel: 0, // 音量级别，用于音浪效果
    iatStatus: '点击录入',
    iatResult: '',
    recordingTimer: null,
    volumeTimer: null, // 新增：音量更新定时器
    touchStartY: 0,
    isWebSocketConnected: false, // 新增：WebSocket连接状态    
    messages: [],
    isStreamingResponse: false, // 新增：是否正在接收流式响应
    currentStreamingIndex: -1, // 新增：当前正在更新的消息索引
});
// 配置 marked
marked.setOptions({
    breaks: true, // 转换换行符为 <br>
    gfm: true, // 启用 GitHub Flavored Markdown
});
// 安全地渲染 Markdown
const renderMarkdown = (markdown) => {
    if (!markdown) return "";
    // 先转换为 HTML
    const html = marked(markdown);

    // 然后清理 HTML 防止 XSS
    return sanitizeHtml(html, {
        allowedTags: sanitizeHtml.defaults.allowedTags.concat([
            "img",
            "h1",
            "h2",
            "h3",
            "h4",
        ]),
        allowedAttributes: {
            ...sanitizeHtml.defaults.allowedAttributes,
            a: ["href", "name", "target", "rel"],
            img: ["src", "alt", "title"],
        },
        allowedSchemes: ["http", "https", "mailto", "data"],
        transformTags: {
            a: (tagName, attribs) => {
                // 确保外部链接有 rel="noopener noreferrer"
                if (attribs.href && attribs.href.startsWith("http")) {
                    return {
                        tagName: "a",
                        attribs: {
                            ...attribs,
                            target: "_blank",
                            rel: "noopener noreferrer",
                        },
                    };
                }
                return { tagName, attribs };
            },
        },
    });
};
// 发送消息给AI接口
const sendMessage = async (text) => {
    const item = {
        student: sessionStorage.getItem('studentNumber'),
        text
    };

    // 创建AbortController用于终止请求
    dataVal.abortController = new AbortController();
    dataVal.isAIResponding = true;
    dataVal.currentResponse = "";

    try {
        const res = await $http.post("/student/generateImages", item);

        if (res && res.data) {
            // const item = JSON.parse(res.data.data);

            // 只有在 conversationId 为空时才更新它
            if (!dataVal.conversationId) {
                dataVal.conversationId = item.conversation_id;
            }
            res.data.text = text
            emits('answer', res.data)

        } else {
            addMessage("抱歉，我没有理解您的问题，请换个方式提问。", false, false);
        }
    } catch (error) {
        if (error.name !== "AbortError") {
            console.info("请求失败: " + error.message);
            addMessage("网络请求失败，请稍后重试。", false, false);
        }
    } finally {
        dataVal.isAIResponding = false;
        dataVal.abortController = null;
        dataVal.currentResponse = "";
        dataVal.inputValue = "";
        dataVal.isStreamingResponse = false; // 结束流式响应
        dataVal.currentStreamingIndex = -1; // 重置当前流式消息索引
    }
};
// 添加消息到聊天窗口（修改版）
const addMessage = (text, isSent, isVoice = false, isStreaming = false) => {
    if (!text) return;

    const processedText = isSent ? text : renderMarkdown(text);

    // 如果是流式响应且已有正在更新的消息
    if (isStreaming && dataVal.isStreamingResponse && dataVal.currentStreamingIndex >= 0) {
        // 更新现有消息
        const message = dataVal.messages[dataVal.currentStreamingIndex];
        message.text = processedText;
        message.rawText = text;
        message.time = new Date().toLocaleTimeString([], {
            hour: "2-digit",
            minute: "2-digit",
        });
        message.isStreaming = true

        // 触发更新
        dataVal.messages = [...dataVal.messages];
    } else {
        // 创建新消息
        const message = {
            text: processedText,
            isSent,
            time: new Date().toLocaleTimeString([], {
                hour: "2-digit",
                minute: "2-digit",
            }),
            isVoice,
            isStreaming: false,
            rawText: text, // 保留原始文本以备后用
        };

        dataVal.messages.push(message);

        // 如果是流式响应的开始，记录索引
        if (isStreaming) {
            dataVal.currentStreamingIndex = dataVal.messages.length - 1;
        }
    }

    emits("add", dataVal.messages || null, isSent, false);
};
// 初始化讯飞语音服务
const initIatService = () => {
    iatService.value = new IatService(appId, apiKey, apiSecret);

    iatService.value.setCallbacks(
        (result) => {
            dataVal.iatResult = result;

            dataVal.isStreamingResponse = true;
            // 添加用户消息
            addMessage(result, true, true, true);
            closeToast();
        },
        (status) => {
            dataVal.iatStatus = status;

            // 监听WebSocket连接成功状态
            if (status.includes('连接成功') || status.includes('录音中')) {
                dataVal.isWebSocketConnected = true;
                // WebSocket连接成功后启动录音
                if (recorder.value && !dataVal.recording) {
                    startAudioRecording();
                }
            } else if (status.includes('关闭') || status.includes('错误')) {
                dataVal.isWebSocketConnected = false;
            }
        }
    );
};

// 初始化RecorderManager
const initRecorderManager = () => {
    try {
        // 使用全局的RecorderManager
        recorder.value = new RecorderManager(path.join(import.meta.env.BASE_URL, import.meta.env.DEV ? "src/utils/iat/dist" : "assets/utils/iat/dist"));
        // recorder.value = new RecorderManager(new URL("@/utils/iat/dist", import.meta.url));
        // 设置录音开始回调
        recorder.value.onStart = () => {
            dataVal.recording = true;
            // dataVal.showRecordingPopup = true;
            dataVal.recordingDuration = 0;

            // 设置计时器
            dataVal.recordingTimer = setInterval(() => {
                dataVal.recordingDuration++;
                if (dataVal.recordingDuration >= 60) {
                    stopRecording();
                }
            }, 1000);

            // 开始更新音量级别（音浪效果）
            startVolumeMonitoring();
        };

        // 设置录音帧回调
        recorder.value.onFrameRecorded = ({ isLastFrame, frameBuffer }) => {
            // console.log('收到音频帧，长度:', frameBuffer.byteLength, '是否是最后一帧:', isLastFrame);

            if (iatService.value) {
                iatService.value.sendAudioData(frameBuffer, isLastFrame);
            }
        };

        // 设置录音停止回调
        recorder.value.onStop = () => {
            if (dataVal.recordingTimer) {
                clearInterval(dataVal.recordingTimer);
                dataVal.recordingTimer = null;
            }

            // 停止音量监控
            stopVolumeMonitoring();

            dataVal.recording = false;
            dataVal.showRecordingPopup = false;

            // 处理识别结果
            setTimeout(() => {
                if (dataVal.iatResult && dataVal.iatResult.trim() && !dataVal.isCanceling) {
                    showToast("识别成功");
                    console.log("最终识别结果:", dataVal.iatResult);

                    sendMessage(dataVal.iatResult);
                } else if (!dataVal.isCanceling) {
                    showToast("未识别到语音内容");
                }
                dataVal.iatResult = '';
            }, 500);
        };

        // 设置录音错误回调
        recorder.value.onError = (error) => {
            console.error('录音错误:', error);
            showToast("录音出错: " + error.message);
            dataVal.recording = false;
            dataVal.showRecordingPopup = false;

            // 停止音量监控
            stopVolumeMonitoring();
        };

        console.log('RecorderManager初始化成功');
        return true;
    } catch (error) {
        console.error("RecorderManager初始化失败:", error);
        showToast("录音初始化失败");
        return false;
    }
};

// 开始音量监控（用于音浪效果）
const startVolumeMonitoring = () => {
    // 清除现有的定时器（如果有）
    if (dataVal.volumeTimer) {
        clearInterval(dataVal.volumeTimer);
    }

    // 设置定时器模拟音量变化（实际应用中应该使用真实的音频分析）
    dataVal.volumeTimer = setInterval(() => {
        // 这里模拟随机音量变化，实际应用中应该使用音频分析API
        // 例如：使用AnalyserNode获取实时音量数据
        const randomVolume = Math.random() * 100;
        dataVal.volumeLevel = randomVolume;
    }, 100); // 每100毫秒更新一次
};

// 停止音量监控
const stopVolumeMonitoring = () => {
    if (dataVal.volumeTimer) {
        clearInterval(dataVal.volumeTimer);
        dataVal.volumeTimer = null;
    }
    dataVal.volumeLevel = 0; // 重置音量级别
};

// 启动音频录音
const startAudioRecording = () => {
    if (!recorder.value) {
        console.error('RecorderManager未初始化');
        return;
    }

    try {
        recorder.value.start({
            sampleRate: 16000, // 设置采样率为16kHz
            frameSize: 1280, // 设置帧大小
        });
    } catch (error) {
        console.error('启动录音失败:', error);
        showToast("启动录音失败");
    }
};

// 添加测试连接的功能
const testConnection = async () => {
    try {
        showToast("测试连接中...");

        if (!iatService.value) {
            initIatService();
        }

        // 只测试WebSocket连接，不录音
        const testWs = new WebSocket(iatService.value._getWebSocketUrl());

        testWs.onopen = () => {
            console.log('测试连接成功');
            showToast("连接测试成功");
            setTimeout(() => {
                testWs.close()
            }, 30000)
        };

        testWs.onclose = (e) => {
            console.log('测试连接已关闭', e);
        }

        testWs.onerror = (e) => {
            console.error('测试连接失败:', e);
            showToast("连接测试失败");
        };

        // 5秒超时
        setTimeout(() => {
            if (testWs.readyState === WebSocket.CONNECTING) {
                testWs.close();
                showToast("连接超时");
            }
        }, 5000);

    } catch (error) {
        console.error('测试连接异常:', error);
        showToast("测试连接异常");
    }
};

// 修改开始录音函数
const startRecording = async (event) => {
    if (event && event.touches && event.touches[0]) {
        dataVal.touchStartY = event.touches[0].clientY;
    }

    try {

        if (!iatService.value) {
            initIatService();
        }

        // 初始化RecorderManager
        if (!recorder.value) {
            const initSuccess = initRecorderManager();
            if (!initSuccess) return;
        }

        console.log('开始建立WebSocket连接...');
        const connected = iatService.value.startRecording();

        if (!connected) {
            showToast("连接语音服务失败");
            console.error('连接失败原因:', dataVal.iatStatus);
            return;
        }

        // 设置超时，如果WebSocket连接成功但录音没启动，自动启动录音
        setTimeout(() => {
            if (dataVal.isWebSocketConnected && !dataVal.recording) {
                console.log('WebSocket已连接，但录音未启动，尝试启动录音');
                startAudioRecording();
            }
        }, 1000);

    } catch (error) {
        console.error("开始录音失败:", error);
        showToast("开始录音失败: " + error.message);
    }
};

// 停止录音
const stopRecording = () => {
    if (!dataVal.recording) return;

    if (recorder.value) {
        recorder.value.stop();
    }

    if (iatService.value) {
        iatService.value.stopRecording();
    }

    dataVal.isCanceling = false;
};

// 处理触摸移动（用于上滑取消）
const handleTouchMove = (event) => {
    if (!dataVal.recording) return;

    const touchY = event.touches[0].clientY;
    const deltaY = dataVal.touchStartY - touchY;

    if (deltaY > 50) {
        dataVal.isCanceling = true;
    } else if (deltaY < 30) {
        dataVal.isCanceling = false;
    }
};

onMounted(() => {
    initIatService();
    document.addEventListener("touchmove", handleTouchMove);
});

onUnmounted(() => {
    if (recorder.value) {
        recorder.value.stop();
    }
    if (iatService.value) {
        iatService.value.stopRecording();
    }
    document.removeEventListener("touchmove", handleTouchMove);

    if (dataVal.recordingTimer) {
        clearInterval(dataVal.recordingTimer);
    }

    // 清除音量监控定时器
    if (dataVal.volumeTimer) {
        clearInterval(dataVal.volumeTimer);
    }
});
</script>

<template>
    <div class="ai-bottom">
        <div class="aibox d-flex space-around align-items-center">
            <div class="voice-btn" :class="{ canceling: dataVal.isCanceling }" @touchstart="startRecording"
                @touchend="stopRecording"><van-icon :name="dataVal.huatong" size="26" class="mode-switch-icon " />
                {{ dataVal.iatStatus }}
            </div>
        </div>

        <!-- 显示识别结果 -->
        <!-- <div v-if="dataVal.iatResult" class="recognition-result">
            <div class="result-label">识别结果:</div>
            <div class="result-text">{{ dataVal.iatResult }}</div>
        </div> -->

        <!-- 录音提示弹窗 -->
        <van-popup v-model:show="dataVal.showRecordingPopup" :overlay="false" round position="center"
            :style="{ height: '30%', width: '50%' }">
            <div class="recording-popup">
                <div class="volume-indicator">
                    <div v-for="i in 5" :key="i" class="volume-bar" :class="{
                        active: dataVal.volumeLevel > (i - 1) * 20,
                    }" :style="{ height: `${i * 15}px` }"></div>
                </div>

                <div class="recording-status d-flex align-items-center">
                    <van-icon name="delete" size="24" v-if="dataVal.isCanceling" />
                    <van-icon name="volume-o" size="24" v-else />
                    <div class="status-text ml-2">
                        {{
                            dataVal.isCanceling
                                ? "上滑取消录音"
                                : "录音中..."
                        }}
                    </div>
                </div>

                <div class="recording-timer">
                    {{ dataVal.recordingDuration }}秒
                </div>

                <div class="recording-tip">最长可录音60秒</div>
            </div>
        </van-popup>
    </div>
</template>

<style scoped lang="scss">
/* 保持您原有的样式不变 */
.ai-bottom {
    width: 100%;
    box-sizing: border-box;
    padding: 0 20px 20px;

    .aibox {
        // background-color: #fff;
        // padding: 0 6px;
        // border-radius: 20px;
        // box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
    }

    .recognition-result {
        margin-top: 10px;
        padding: 10px;
        background-color: #f9f9f9;
        border-radius: 8px;

        .result-label {
            font-weight: bold;
            margin-bottom: 5px;
            color: #333;
        }

        .result-text {
            color: #666;
        }
    }

    .tips {
        color: #999;
    }
}

.voice-btn {
    width: 200px;
    height: 60px;
    margin: 0 10px;
    background: #E95294;
    color: #fff;
    border-radius: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    font-weight: bold;
    transition: all 0.3s;

    &:active {
        background-color: #e0e0e0;
    }

    &.canceling {
        background-color: #ffeceb;
        color: #ff4d4f;
    }
}

.voice-container {
    display: flex;
    align-items: center;
    width: calc(100% - 40px);
    height: 50px;
    padding: 0 10px;

    .mode-switch-icon {
        margin-right: 15px;
    }


}

.recording-popup {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;

    .volume-indicator {
        display: flex;
        align-items: flex-end;
        justify-content: center;
        gap: 8px;
        height: 60px;
        margin-bottom: 20px;

        .volume-bar {
            width: 8px;
            background-color: #e0e0e0;
            border-radius: 4px;
            transition: background-color 0.2s;

            &.active {
                background-color: #07c160;
            }
        }
    }

    .recording-status {
        .status-text {
            font-size: 16px;
            color: #333;
        }
    }

    .recording-timer {
        font-size: 24px;
        font-weight: bold;
        color: #333;
        margin-bottom: 10px;
    }

    .recording-tip {
        font-size: 14px;
        color: #999;
    }
}
</style>